﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Diagnostics;

namespace ElevateThis
{
    /// <summary>
    /// USAGE:
    /// 
    /// This application can be called from a batch file to re-launch itself elevated.  Insert
    /// the following into the top of your batch file (assumes ElevateThis.exe is in PATH):
    /// 
    ///     ElevateThis.exe /BatchFile %0 /BatchArgs %* && goto :eof
    ///
    /// This will drop straight through if already elevated, or it'll exit the batch file and spawn a
    /// new elevated batch file.
    /// 
    /// </summary>
    class Program
    {
        static int Main(string[] args)
        {
            ExitCode ret = ExitCode.Success;

            try
            {
                // Output diagnostic information - debug build only
                Diagnostics.OutputHeader(args);

                // Turn the command line args into an options class
                var options = CommandLineParser.ParseCommandLine(args);
                Diagnostics.OutputOptions(options);

                // Launch state decides what we do next
                var launchState = CalculateLaunchState(options.LaunchState);

                switch (launchState)
                {
                    case LaunchStates.NotElevated:
                        // Initial call
                        // Re-launch ourselves elevated
                        ret = ProcessLauncher.RelaunchElevated(options);
                        break;
                    case LaunchStates.RelaunchedElevated:
                        // We have been re-launched elevated
                        // Launch the batch file we've been passed
                        ret = ProcessLauncher.LaunchBatchFile(options);
                        break;
                    case LaunchStates.Elevated:
                        // Called from an elevated command prompt
                        // Inform the calling batch file to continue with the rest of its commands
                        ret = ExitCode.Elevated;
                        break;
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine();
                Console.WriteLine("*** ElevateThis did not elevate the batch file:");
                Console.WriteLine("    " + ex.Message);
                Console.WriteLine();
                ret = ExitCode.GeneralError;
            }

            // Final operation in debug build
            Diagnostics.HandleProcessExit(ret);

            return (int)ret;
        }

        /// <summary>
        /// Determines the launch state based on options provided at the command line and whether
        /// this process is elevated
        /// </summary>
        private static LaunchStates CalculateLaunchState(LaunchStates commandLineLaunchState)
        {
            if (commandLineLaunchState == LaunchStates.RelaunchedElevated)
            {
                // Command line tells us that we've been re-launched elevated
                return LaunchStates.RelaunchedElevated;
            }
            else if (UACHelper.IsProcessElevated)
            {
                // Nothing on command line, but we are in an elevated process
                // Ready to continue with the rest of the batch file
                return LaunchStates.Elevated;
            }
            else
            {
                // First call into the process
                return LaunchStates.NotElevated;
            }
        }
    }
}
